www.gusucode.com > VC++ 车牌定位与识别源码程序 > VC++ 车牌定位与识别源码程序/code/PlateReco/PlateRecoView.cpp

    //Download by http://www.NewXing.com
// PlateRecoView.cpp : implementation of the CPlateRecoView class
//

#include "stdafx.h"
#include "PlateReco.h"
#include "MainFrm.h"
#include "DlgRecoResult.h"

#include "PlateRecoDoc.h"
#include "PlateRecoView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView

IMPLEMENT_DYNCREATE(CPlateRecoView, CView)

BEGIN_MESSAGE_MAP(CPlateRecoView, CView)
	//{{AFX_MSG_MAP(CPlateRecoView)
	ON_COMMAND(ID_LPR_platelocation, OnLPRplatelocation)
	ON_COMMAND(ID_LPR_plate2binarycolor, OnLPRplate2binarycolor)
	ON_COMMAND(ID_LPR_platenorm, OnLPRplatenorm)
	ON_COMMAND(ID_LPR_platecharthinning, OnLPRplatecharthinning)
	ON_COMMAND(ID_LPR_feature16seg, OnLPRfeature16seg)
	ON_COMMAND(ID_LPR_platereco, OnLPRplatereco)
	ON_COMMAND(ID_LPR_platepreprocessall, OnLPRplatepreprocessall)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView construction/destruction

CPlateRecoView::CPlateRecoView()
{
	// TODO: add construction code here
	for(int i = 0; i < 13; i++)
	{
		m_fCode13Sect[i] = 0.0;
	}

	for(int j = 0; j < 16; j++)
	{
		m_fCode13Sect[j] = 0.0;
	}
	m_iPlateType = 0;
}

CPlateRecoView::~CPlateRecoView()
{
}

BOOL CPlateRecoView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView drawing

void CPlateRecoView::OnDraw(CDC* pDC)
{
	// 显示等待光标
	BeginWaitCursor();
	
	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	
	// 获取DIB
	HDIB hDIB = pDoc->GetHDIB();
	
	// 判断DIB是否为空
	if (hDIB != NULL)
	{
		LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
		
		// 获取DIB宽度
		int cxDIB = (int) ::DIBWidth(lpDIB);
		
		// 获取DIB高度
		int cyDIB = (int) ::DIBHeight(lpDIB);

		::GlobalUnlock((HGLOBAL) hDIB);
		
		CRect rcDIB;
		rcDIB.top = rcDIB.left = 0;
		rcDIB.right = cxDIB;
		rcDIB.bottom = cyDIB;
		
		CRect rcDest;
		
		// 判断是否是打印
		if (pDC->IsPrinting())
		{
			// 是打印,计算输出图像的位置和大小,以便符合页面
			
			// 获取打印页面的水平宽度(象素)
			int cxPage = pDC->GetDeviceCaps(HORZRES);
			
			// 获取打印页面的垂直高度(象素)
			int cyPage = pDC->GetDeviceCaps(VERTRES);
			
			// 获取打印机每英寸象素数
			int cxInch = pDC->GetDeviceCaps(LOGPIXELSX);
			int cyInch = pDC->GetDeviceCaps(LOGPIXELSY);
			
			// 计算打印图像大小(缩放,根据页面宽度调整图像大小)
			rcDest.top = rcDest.left = 0;
			rcDest.bottom = (int)(((double)cyDIB * cxPage * cyInch)
					/ ((double)cxDIB * cxInch));
			rcDest.right = cxPage;
			
			// 计算打印图像位置(垂直居中)
			int temp = cyPage - (rcDest.bottom - rcDest.top);
			rcDest.bottom += temp/2;
			rcDest.top += temp/2;

		}
		else   
		// 非打印
		{
			// 不必缩放图像
			rcDest = rcDIB;
		}
		
		// 输出DIB
		::PaintDIB(pDC->m_hDC, &rcDest, pDoc->GetHDIB(),
			&rcDIB, pDoc->GetDocPalette());
	}

	CSize sizeTotal(1200,900);
	SetScrollSizes(MM_TEXT, sizeTotal);

	// 恢复正常光标
	EndWaitCursor();
}
void CPlateRecoView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx =1200;
	sizeTotal.cy =900;
	SetScrollSizes(MM_TEXT, sizeTotal);

	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();

	// 指向DIB的指针
	LPSTR lpDIB;
	
	// 锁定DIB
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());

	// 保存原图像大小
	m_iWidth = ::DIBWidth(lpDIB);
	m_iHeight = ::DIBHeight(lpDIB);

/*
	CScrollView::OnInitialUpdate();


	CSize sizeTotal(1000,600);//::DIBWidth(lpDIB), ::DIBHeight(lpDIB));
	SetScrollSizes(MM_TEXT, sizeTotal);
	
	CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd;
	ASSERT_KINDOF(CMainFrame, pAppFrame);
	CRect rc;
	pAppFrame->GetClientRect(&rc);
	if (rc.Width() >= sizeTotal.cx && rc.Height() >= sizeTotal.cy &&
		(sizeTotal.cx>0 || sizeTotal.cy>0))
		ResizeParentToFit(FALSE);
*/
}
/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView printing

BOOL CPlateRecoView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// 设置总页数为一。
	pInfo->SetMaxPage(1);
	
	// default preparation
	return DoPreparePrinting(pInfo);
}


void CPlateRecoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CPlateRecoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView diagnostics

#ifdef _DEBUG
void CPlateRecoView::AssertValid() const
{
	CView::AssertValid();
}

void CPlateRecoView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CPlateRecoDoc* CPlateRecoView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPlateRecoDoc)));
	return (CPlateRecoDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView message handlers

LRESULT CPlateRecoView::OnDoRealize(WPARAM wParam, LPARAM)
{
	ASSERT(wParam != NULL);

	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	
	// 判断DIB是否为空
	if (pDoc->GetHDIB() == NULL)
	{
		// 直接返回
		return 0L;
	}
	
	// 获取Palette
	CPalette* pPal = pDoc->GetDocPalette();
	if (pPal != NULL)
	{
		// 获取MainFrame
		CMainFrame* pAppFrame = (CMainFrame*) AfxGetApp()->m_pMainWnd;
		ASSERT_KINDOF(CMainFrame, pAppFrame);
		
		CClientDC appDC(pAppFrame);

		// All views but one should be a background palette.
		// wParam contains a handle to the active view, so the SelectPalette
		// bForceBackground flag is FALSE only if wParam == m_hWnd (this view)
		CPalette* oldPalette = appDC.SelectPalette(pPal, ((HWND)wParam) != m_hWnd);
		
		if (oldPalette != NULL)
		{
			UINT nColorsChanged = appDC.RealizePalette();
			if (nColorsChanged > 0)
				pDoc->UpdateAllViews(NULL);
			appDC.SelectPalette(oldPalette, TRUE);
		}
		else
		{
			TRACE0("\tCCh1_1View::OnPaletteChanged中调用SelectPalette()失败!\n");
		}
	}
	
	return 0L;
}

/////////////////////////////////////////////////////////////////////////////
// CPlateRecoView message handlers

void CPlateRecoView::OnLPRplatelocation() 
{
	// TODO: Add your command handler code here
	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	
	// 指向DIB的指针
	LPSTR	lpDIB;

	// 指向DIB象素指针
	LPSTR   lpDIBBits;
	
	// 锁定DIB
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
	
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的边缘检测,其它的可以类推)
	if (::DIBNumColors(lpDIB) != 256)
	{
		// 提示用户
		MessageBox("目前只支持256色位图的运算!", "系统提示" , MB_ICONINFORMATION | MB_OK);

		// 解除锁定
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
		
		// 返回
		return;
	}

	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);

	// 指向缓存图像的指针
	LPSTR	lpDst1;
	LPSTR	lpDst2;
	
	// 指向缓存DIB图像的指针
	LPSTR	lpNewDIBBits1;
	HLOCAL	hNewDIBBits1;
	LPSTR	lpNewDIBBits2;
	HLOCAL	hNewDIBBits2;

	int *pPlateLine1,*pPlateLine2;

	// 获取车牌位置信息
	int *pPlatePosition;


	//循环变量
	long i;
	long j;

	for(i=0;i<40;i++)
		m_iPlateLine[i]=0;

	// 指向源图像象素的指针
    unsigned char * lpSrc;
	// 阈值
	BYTE	bThre;
	// 各个灰度值的计数
	LONG lCount[256];

	int temp1,temp2,iOldLeixin1,iOldLeixin2,iNum1,iNum2,iGrayCore1,iGrayCore2,iMeanGray;

	// 参数对话框
	//CDlgBinary  myDlgBinary;


	// 暂时分配内存,以保存新图像
	hNewDIBBits1 = LocalAlloc(LHND, m_iWidth * m_iHeight);

	if (hNewDIBBits1 == NULL)
	{
		// 分配内存失败
		return;
	}
	
	// 锁定内存
	lpNewDIBBits1 = (char * )LocalLock(hNewDIBBits1);

	// 暂时分配内存,以保存新图像
	hNewDIBBits2 = LocalAlloc(LHND, m_iWidth * m_iHeight);

	if (hNewDIBBits2 == NULL)
	{
		// 分配内存失败
		return;
	}
	
	// 锁定内存
	lpNewDIBBits2 = (char * )LocalLock(hNewDIBBits2);
	
    // 拷贝源图像到缓存图像中
	lpDst1 = (char *)lpNewDIBBits1;
	memcpy(lpNewDIBBits1, lpDIBBits, m_iWidth * m_iHeight);
	lpDst2 = (char *)lpNewDIBBits2;
	memcpy(lpNewDIBBits2, lpDIBBits,  m_iWidth * m_iHeight);
	// 复制经过模板运算后的图像到源图像
//	memcpy(lpDIBBits, lpNewDIBBits1,  m_iWidth * m_iHeight);

	// 更改光标形状
	BeginWaitCursor();

////////////////////////////////////////////////////////	
	// 水平差分
	if (DifferDIB(lpDIBBits, WIDTHBYTES(::DIBWidth(lpDIB) * 8), ::DIBHeight(lpDIB)))
	{
		
		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);

		// 更新视图
		pDoc->UpdateAllViews(NULL);
	}
	else
	{
		// 提示用户
		MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
	}

////////////////////////////////////////////////////////
	// 调用HprojectDIB()函数对DIB进行水平投影
	if (pPlateLine1 = HDifferProjDIB4(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB)))
	{
		for(int i=0;i<40;i++)
		{
			m_iPlateLine[i]=*pPlateLine1;
			pPlateLine1++;
		}
		
		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);

		// 更新视图
		pDoc->UpdateAllViews(NULL);
	}
	else
	{
		// 提示用户
		MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
	}

////////////////////////////////////////////////////////
	int iLineNumber=0;
	for(iLineNumber=0;iLineNumber<40;iLineNumber++)
	{
	////////////////////////////////////////////////////////
		// 复制原图象
		memcpy(lpDIBBits, lpNewDIBBits1,  m_iWidth * m_iHeight);

		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);

		// 更新视图
		pDoc->UpdateAllViews(NULL);

//		AfxMessageBox("又一次");

	////////////////////////////////////////////////////////
        // 边缘检测
		pPlateLine2 = &m_iPlateLine[iLineNumber];
		// 调用SobelDIB()函数对DIB进行边缘检测
		if (PlateDIB1(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB),pPlateLine2))
		{
			
			// 设置脏标记
			pDoc->SetModifiedFlag(TRUE);

			// 更新视图
			pDoc->UpdateAllViews(NULL);
		}
		else
		{
			// 提示用户
			MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
		}

	////////////////////////////////////////////////////////
		// 二值化

		// 重置计数为0
		for (i = 0; i < 256; i ++)
		{
			// 清零
			lCount[i] = 0;
		}
		
		// 图像每行的字节数
		LONG lLineBytes;
		
		// 计算图像每行的字节数
		lLineBytes = WIDTHBYTES(m_iWidth * 8);
		
		// 计算各个灰度值的计数
		for (i = 0; i < m_iHeight; i ++)
		{
			for (j = 0; j < m_iWidth; j ++)
			{
				lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
				
				// 计数加1
				lCount[*(lpSrc)]++;
			}
		}

		// 计算平均灰度值
		iMeanGray = 0;
		for(i = 1; i < 255; i++)
		{
			iMeanGray += i * lCount[i];
		}
		iMeanGray = (int)iMeanGray / (m_iHeight * m_iWidth);

		// 初始的类心,可任意设定
		iGrayCore1 = (int)(iMeanGray/2);
		iGrayCore2 = (int)(iMeanGray+(255-iMeanGray)/2);



		do  // K-均值聚类分析
		{
			iNum1 = 0;
			iNum2 = 0;
			temp1 = 0;
			temp2 = 0;
			iOldLeixin1 = iGrayCore1;
			iOldLeixin2 = iGrayCore2;

			for(i = 0; i < m_iHeight; i++)
			{
				for(j = 0; j < m_iWidth; j++)
				{
					lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
					if(abs(iGrayCore1-*lpSrc)<=abs(iGrayCore2-*lpSrc))
					{
						temp1 += *lpSrc;
						iNum1++;
					}
					else
					{
						temp2 += *lpSrc;
						iNum2++;
					}
				}
			}
			iGrayCore1 = (int)(temp1/iNum1);
			iGrayCore2 = (int)(temp2/iNum2);
		}while((iGrayCore1!=iOldLeixin1)||(iGrayCore2!=iOldLeixin2));
			

		
		bThre  = iGrayCore2+30;
		
		// 删除对话框
	//	delete myDlgBinary;	
		
		// 更改光标形状
		BeginWaitCursor();
		
		// 调用ThresholdTrans()函数进行阈值变换
		ThresholdTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bThre);
		
		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);
		
		// 更新视图
		pDoc->UpdateAllViews(NULL);

	///////////////////////////////////////////////////////
		// 提取车牌
		// 缩放后图像的宽度和高度
		LONG	lNewWidth = 140;
		LONG	lNewHeight = 40;
		
		// 缩放后图像的宽度(lNewWidth',必须是4的倍数)
		LONG	lNewLineBytes;
				
		// 创建新DIB
		HDIB hNewDIB = NULL;
			
		// 指向缩放图像的指针
		LPSTR	lpNewDIB ;
		
		// 指向BITMAPINFO结构的指针(Win3.0)
		LPBITMAPINFOHEADER lpbmi;
		
		// 指向BITMAPCOREINFO结构的指针
		LPBITMAPCOREHEADER lpbmc;
		
		// 计算新图像每行的字节数
		lNewLineBytes = WIDTHBYTES(lNewWidth * 8);
		
		// 更改光标形状
		BeginWaitCursor();

		// 找到DIB图像象素起始位置
		lpDIBBits = ::FindDIBBits(lpDIB);

		pPlatePosition = RowscanDIB3 (lpDIBBits,lpNewDIBBits1,::DIBWidth(lpDIB), ::DIBHeight(lpDIB), pPlateLine2);

		for(i=0;i<5;i++)
		{
			m_iPlatePosition[i] = *pPlatePosition;
			pPlatePosition++;
		}

		if(m_iPlatePosition[0]==1)
		{
//			AfxMessageBox("找到了!");

			// 显示车牌位置信息
	//		CDlgShowPlate dlgShowPlate;
	//		dlgShowPlate.m_iTop   = ::DIBHeight(lpDIB) - m_iPlatePosition[0];
	//		dlgShowPlate.m_iLow   = ::DIBHeight(lpDIB) - m_iPlatePosition[1];
	//		dlgShowPlate.m_iLeft  = m_iPlatePosition[2];
	//		dlgShowPlate.m_iRight = m_iPlatePosition[3];

	//		dlgShowPlate.DoModal();

			// 分配内存,以保存新DIB
			hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * lNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
			
			// 判断是否内存分配失败
			if (hNewDIB != NULL)
			{
				lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hNewDIB);
				
				// 复制DIB信息头、调色板和车牌图像
				memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB) + lNewLineBytes * lNewHeight);
					
				// 获取指针
				lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
				lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
				
				// 更新DIB中图像的高度和宽度
				if (IS_WIN30_DIB(lpNewDIB))
				{
					// 对于Windows 3.0 DIB
					lpbmi->biWidth = lNewWidth;
					lpbmi->biHeight = lNewHeight;
				}
				else
				{
					// 对于其它格式的DIB
					lpbmc->bcWidth = (unsigned short) lNewWidth;
					lpbmc->bcHeight = (unsigned short) lNewHeight;
				}
					
	//			TRACE("\n*******%d*******\n",m_iPlatePosition[0]);

				// 替换DIB,同时释放旧DIB对象
				pDoc->ReplaceHDIB(hNewDIB);

				// 更新DIB大小和调色板
				pDoc->InitDIBData();

				// 设置脏标记
				pDoc->SetModifiedFlag(TRUE);

				// 更新视图
				pDoc->UpdateAllViews(NULL);
			}
		}		
		else
		{
			// 提示用户
//			AfxMessageBox("这次没找到!");
		}
	
		if( (m_iPlateLine[iLineNumber+2]>=0)||((m_iPlatePosition[0]==1)))
			break;
	}



	// 释放内存
	LocalUnlock(hNewDIBBits1);
	LocalFree(hNewDIBBits1);

	LocalUnlock(hNewDIBBits2);
	LocalFree(hNewDIBBits2);
	
	// 解除锁定
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());

	// 恢复光标
	EndWaitCursor();		
	
}

void CPlateRecoView::OnLPRplate2binarycolor() 
{
	// TODO: Add your command handler code here
	// 二值化
	
	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	
	// 指向DIB的指针
	LPSTR	lpDIB;
	
	// 指向DIB象素指针
	LPSTR   lpDIBBits;
	
	// 参数对话框
	//CDlgBinary  myDlgBinary;
	
	// 阈值
	BYTE	bThre;
	
	// 锁定DIB
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
	
	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的阈值变换,其它的可以类推)
	if (::DIBNumColors(lpDIB) != 256)
	{
		// 提示用户
		MessageBox("目前只支持256色位图的阈值变换!", "系统提示" , 
			MB_ICONINFORMATION | MB_OK);
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
		
		// 返回
		return;
	}


	// 各个灰度值的计数
	LONG lCount[256];

	int temp1,temp2,iOldLeixin1,iOldLeixin2,iNum1,iNum2,iGrayCore1,iGrayCore2,iMeanGray;
	// 指向源图像象素的指针

	unsigned char * lpSrc;
	
	// 循环变量
	LONG i;
	LONG j;


	// 重置计数为0
	for (i = 0; i < 256; i ++)
	{
		// 清零
		lCount[i] = 0;
	}
	
	// 车牌图像的长、宽
	int iWidth;
	int iHeight;

	iWidth = ::DIBWidth(lpDIB);
	iHeight = ::DIBHeight(lpDIB);

	// 图像每行的字节数
	LONG lLineBytes;
	
	// 计算图像每行的字节数
	lLineBytes = WIDTHBYTES(iWidth * 8);
	
	// 计算各个灰度值的计数
	for (i = 0; i < iHeight; i ++)
	{
		for (j = 0; j < iWidth; j ++)
		{
			lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
			
			// 计数加1
			lCount[*(lpSrc)]++;
		}
	}

	// 计算平均灰度值
	iMeanGray = 0;
	for(i = 1; i < 255; i++)
	{
		iMeanGray += i * lCount[i];
	}
	iMeanGray = (int)iMeanGray / (iHeight * iWidth);

    // 初始的类心,可任意设定
	iGrayCore1 = (int)(iMeanGray/2);
	iGrayCore2 = (int)(iMeanGray+(255-iMeanGray)/2);



	do  // K-均值聚类分析
	{
		iNum1 = 0;
		iNum2 = 0;
		temp1 = 0;
		temp2 = 0;
		iOldLeixin1 = iGrayCore1;
		iOldLeixin2 = iGrayCore2;

		for(i = 0; i < iHeight; i++)
		{
			for(j = 0; j < iWidth; j++)
			{
				lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
				if(abs(iGrayCore1-*lpSrc)<=abs(iGrayCore2-*lpSrc))
				{
					temp1 += *lpSrc;
					iNum1++;
				}
				else
				{
					temp2 += *lpSrc;
					iNum2++;
				}
			}
		}
		iGrayCore1 = (int)(temp1/iNum1);
		iGrayCore2 = (int)(temp2/iNum2);
	}while((iGrayCore1!=iOldLeixin1)||(iGrayCore2!=iOldLeixin2));
		

	// 初始化变量值
	//myDlgBinary.m_bThre = iGrayCore2-20;

	/* 显示对话框,提示用户设定阈值
	if (myDlgBinary.DoModal() != IDOK)
	{
		// 返回
		return;
	}*/
	
	// 获取用户设定的阈值
	bThre = 112; //myDlgBinary.m_bThre;
	
	// 删除对话框
	//delete myDlgBinary;	
	
	// 更改光标形状
	BeginWaitCursor();
	
	// 调用ThresholdTrans()函数进行阈值变换
	ThresholdTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), bThre);
	
	// 设置脏标记
	pDoc->SetModifiedFlag(TRUE);
	
	// 更新视图
	pDoc->UpdateAllViews(NULL);
	
	// 解除锁定
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
	
	// 恢复光标
	EndWaitCursor();	
}

void CPlateRecoView::OnLPRplatenorm() 
{
	// TODO: Add your command handler code here
	// 字符归一化
	
	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	
	// 指向DIB的指针
	LPSTR	lpDIB;
	
	// 指向DIB象素指针
	LPSTR   lpDIBBits;
	LPSTR   lpNewDIBBits2;
	

	// 字符归一化后的新的高度与宽度
	int iNewWidth;
	int iOldHeight;
	int iNewHeight;
	int* pNewHeight;
	int iTemp;
	

	// 锁定DIB
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());

	iNewWidth = ::DIBWidth(lpDIB);	
	iOldHeight = ::DIBHeight(lpDIB);

	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的阈值变换,其它的可以类推)
	if (::DIBNumColors(lpDIB) != 256)
	{
		// 提示用户
		MessageBox("目前只支持256色位图的阈值变换!", "系统提示" , 
			MB_ICONINFORMATION | MB_OK);
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
		
		// 返回
		return;
	}

	// 更改光标形状
	BeginWaitCursor();
	pNewHeight = RowscanDIB4(lpDIBBits,::DIBWidth(lpDIB), ::DIBHeight(lpDIB));

	iTemp = *pNewHeight;
	pNewHeight++;
	iNewHeight = *pNewHeight;
	iNewHeight = abs(iNewHeight - iTemp);


	// 缩放后图像的宽度(lNewWidth',必须是4的倍数)
	LONG	lNewLineBytes;
			
	// 创建新DIB
	HDIB hNewDIB = NULL;
		
	// 指向缩放图像的指针
	LPSTR	lpNewDIB ;

	// 指向缩放图像的指针
	LPSTR   lpNewDIB2;
	
	// 指向BITMAPINFO结构的指针(Win3.0)
	LPBITMAPINFOHEADER lpbmi;
	
	// 指向BITMAPCOREINFO结构的指针
	LPBITMAPCOREHEADER lpbmc;

	// 计算新图像每行的字节数
	lNewLineBytes = WIDTHBYTES(iNewWidth * 8);
	

	// 分配内存,以保存新DIB
	hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewLineBytes * iNewHeight + *(LPDWORD)lpDIB + ::PaletteSize(lpDIB));
	
	// 判断是否内存分配失败
	if (hNewDIB != NULL)
	{
		lpNewDIB =  (char * )::GlobalLock((HGLOBAL) hNewDIB);
		
		// 复制DIB信息头、调色板和车牌图像
		memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + ::PaletteSize(lpDIB) + lNewLineBytes * iNewHeight);
			
		// 获取指针
		lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
		lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
		
		// 更新DIB中图像的高度和宽度
		if (IS_WIN30_DIB(lpNewDIB))
		{
			// 对于Windows 3.0 DIB
			lpbmi->biWidth = iNewWidth;
			lpbmi->biHeight = iNewHeight;
		}
		else
		{
			// 对于其它格式的DIB
			lpbmc->bcWidth = (unsigned short) iNewWidth;
			lpbmc->bcHeight = (unsigned short) iNewHeight;
		}
			
//			TRACE("\n*******%d*******\n",m_iPlatePosition[0]);

		// 替换DIB,同时释放旧DIB对象
		pDoc->ReplaceHDIB(hNewDIB);

		// 更新DIB大小和调色板
		pDoc->InitDIBData();

		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);

		// 更新视图
//		pDoc->UpdateAllViews(NULL);
	}

	LocalUnlock(lpDIB);
	LocalFree(lpDIB);

	// 创建新DIB
	HDIB hNewDIB2 = NULL;
	
	// 更改光标形状
	BeginWaitCursor();

	float fXZoomRatio = 1.0;
	float fYZoomRatio;

	fYZoomRatio = (float)iOldHeight / (float)::DIBHeight(lpNewDIB);
	
	// 调用ZoomDIB()函数转置DIB
	hNewDIB2 = (HDIB) ZoomDIB(lpNewDIB, fXZoomRatio, fYZoomRatio);



	// 判断缩放是否成功
	if (hNewDIB2 != NULL)
	{
		
		// 替换DIB,同时释放旧DIB对象
		pDoc->ReplaceHDIB(hNewDIB2);

		// 更新DIB大小和调色板
		pDoc->InitDIBData();
		
		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);

	    lpNewDIB2 =  (char * )::GlobalLock((HGLOBAL) hNewDIB2);	
		
		// 重新设置滚动视图大小
		SetScrollSizes(MM_TEXT, pDoc->GetDocSize());

		// 更新视图
//		pDoc->UpdateAllViews(NULL);
	}
	else
	{
		// 提示用户
		MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
	}

	LocalUnlock(lpNewDIB);
	LocalFree(lpNewDIB);	


	// 找到DIB图像象素起始位置
	lpNewDIBBits2 = ::FindDIBBits(lpNewDIB2);

	// 调用ThresholdTrans()函数进行阈值变换
	if(CharacterUnit(lpNewDIBBits2, ::DIBWidth(lpNewDIB2), ::DIBHeight(lpNewDIB2)) != TRUE)
	{
		return;
	}

	// 设置脏标记
	pDoc->SetModifiedFlag(TRUE);

	// 更新视图
	pDoc->UpdateAllViews(NULL);

	// 解除锁定
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
	
	// 恢复光标
	EndWaitCursor();		
}

void CPlateRecoView::OnLPRplatecharthinning() 
{
	// TODO: Add your command handler code here

	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	
	// 指向DIB的指针
	LPSTR lpDIB;
	
	// 指向DIB象素指针
	LPSTR    lpDIBBits;
	
	// 线性变换的斜率
	FLOAT fA;
	
	// 线性变换的截距
	FLOAT fB;
	
	// 反色操作的线性变换的方程是-x + 255
	fA = -1.0;
	fB = 255.0;
	
	// 锁定DIB
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());

	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的反色,其它的可以类推)
	if (::DIBNumColors(lpDIB) != 256)
	{
		// 提示用户
		MessageBox("目前只支持256色位图的反色!", "系统提示" , MB_ICONINFORMATION | MB_OK);
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
		
		// 返回
		return;
	}
	
	// 更改光标形状
	BeginWaitCursor();
	
	// 调用LinerTrans()函数反色
	LinerTrans(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), fA, fB);
	
	// 设置脏标记
	pDoc->SetModifiedFlag(TRUE);
	
	// 更新视图
//	pDoc->UpdateAllViews(NULL);
	
	// 解除锁定
//	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());

	// 恢复光标
//	EndWaitCursor();	

	// 找到DIB图像象素起始位置
//	lpDIBBits = ::FindDIBBits(lpDIB);
	
	// 调用ThiningDIB()函数对DIB进行闭运算
	if (ThiningDIB(lpDIBBits, WIDTHBYTES(::DIBWidth(lpDIB) * 8), ::DIBHeight(lpDIB)))
	{
		
		// 设置脏标记
		pDoc->SetModifiedFlag(TRUE);

		// 更新视图
		pDoc->UpdateAllViews(NULL);
	}
	else
	{
		// 提示用户
		MessageBox("分配内存失败或者图像中含有0和255之外的像素值!", "系统提示" , MB_ICONINFORMATION | MB_OK);
	}
	
	// 解除锁定
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());

	// 恢复光标
	EndWaitCursor();		
}


void CPlateRecoView::OnLPRfeature16seg() 
{
	// TODO: Add your command handler code here
	// 基于13段投影法的特征提取
	// 获取文档
	CPlateRecoDoc* pDoc = GetDocument();
	
	// 指向DIB的指针
	LPSTR	lpDIB;
	
	// 指向DIB象素指针
	LPSTR    lpDIBBits;
	
	// 锁定DIB
	lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
	
	// 找到DIB图像象素起始位置
	lpDIBBits = ::FindDIBBits(lpDIB);

	// 用于传递13段投影编码表
	float* pCode16Section;
	float fCode16Sect[6][16];

	FILE *fpPlateCharData;
	char *pPlateCharDataFileName = "识别数据_16段映射.txt ";

	LONG i,j;
	
	// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的沃尔什-哈达玛变换,其它的可以类推)
	if (::DIBNumColors(lpDIB) != 256)
	{
		// 提示用户
		MessageBox("目前只支持256色位图的沃尔什-哈达玛变换!", "系统提示" ,
			MB_ICONINFORMATION | MB_OK);
		
		// 解除锁定
		::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
		
		// 返回
		return;
	}

    pCode16Section = CharExtract16Sect(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB));

//	TRACE("\n");
	for(i=0;i<6;i++)
	{
		for(j=0;j<16;j++)
		{
			fCode16Sect[i][j] = *pCode16Section;
			m_fCode16Sect[i][j] = fCode16Sect[i][j];
			pCode16Section++;
		}
//		TRACE("\t%f",m_fCode13Sect[i]);
	}

	if((fpPlateCharData = fopen(pPlateCharDataFileName,"w+"))==NULL)
	{
		AfxMessageBox("   无法正确创建文件!\n请检查您代码中的文件名!");
		return;
	}
	int q1=0;
	// 将提取出的各字符的特征量存成文件

	// 将指针移到文件头
	fseek(fpPlateCharData,0l,SEEK_SET);
	for(i = 0; i < 6; i++)
	{
		for(j = 0; j < 16; j++)
		{
//			fprintf(fpHidWeight,"%f",fHidWeight[i][j]);
			fprintf(fpPlateCharData,"%10f",fCode16Sect[i][j]);
		}
		fprintf(fpPlateCharData,"\n","");
		if(i==5)
			fprintf(fpPlateCharData,"\n","");
	}
	fclose(fpPlateCharData);
//	TRACE("\n");

	// 解除锁定
	::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());

	// 更改光标形状
	BeginWaitCursor();	
}

void CPlateRecoView::OnLPRplatereco() 
{
	OnLPRfeature16seg();

	CPlateRecoDoc* pDoc = GetDocument();

	float* pReco16Section;

//	CString strRecoChars,strTemp;

	CDlgRecoResult myDlgRecoResult;

	pReco16Section = &m_fCode16Sect[0][0];

	// 字符识别
	m_cRecoChar[0] = BPReco16SectionLetter(pReco16Section);

	pReco16Section = &m_fCode16Sect[1][0];
	if(m_iPlateType==0)
	{	
		m_cRecoChar[1] = BPReco16SectionLetter(pReco16Section);
	}
	else
	{
		m_cRecoChar[1] = BPReco16SectionNumber(pReco16Section);
	}
//	strTemp.Format("%c",m_cRecoChar[0]);
	pReco16Section = &m_fCode16Sect[2][0];
	m_cRecoChar[2] = BPReco16SectionNumber(pReco16Section);

	pReco16Section = &m_fCode16Sect[3][0];
	m_cRecoChar[3] = BPReco16SectionNumber(pReco16Section);

	pReco16Section = &m_fCode16Sect[4][0];
	m_cRecoChar[4] = BPReco16SectionNumber(pReco16Section);

	pReco16Section = &m_fCode16Sect[5][0];
	m_cRecoChar[5] = BPReco16SectionNumber(pReco16Section);


	
	myDlgRecoResult.m_cRecoChar[0]= m_cRecoChar[0];
	myDlgRecoResult.m_cRecoChar[1]= m_cRecoChar[1];
	myDlgRecoResult.m_cRecoChar[2]= m_cRecoChar[2];
	myDlgRecoResult.m_cRecoChar[3]= m_cRecoChar[3];
	myDlgRecoResult.m_cRecoChar[4]= m_cRecoChar[4];
	myDlgRecoResult.m_cRecoChar[5]= m_cRecoChar[5];


	myDlgRecoResult.DoModal();

	delete myDlgRecoResult;

	return;		
}

void CPlateRecoView::OnLPRplatepreprocessall() 
{
	OnLPRplatelocation(); 
	OnLPRplate2binarycolor();
	OnLPRplatenorm();
	OnLPRplatecharthinning();

}